# -*- coding: utf-8 -*-
import pymongo
import time
import types
import logging


from hashlib import md5


###
from common import BaseHandler, clear_cache_multi, decode_dict, encode_dict
from config import *
import bson

conn = pymongo.Connection(host=MONGO_HOST,port=MONGO_PORT)
mongo = conn.data
class User:
    def __init__(self):
        self.collection = mongo.user
        pass
    
    def newUser(self,data):
        self.collection.insert(data)
        
    def hasReg(self,username):
        ret = self.collection.find({"name":username}).count()
        return ret > 0
    
    def checkPasswd(self,username,passwd):
        ret = self.collection.find({"name":username,"code":passwd}).count()
        return ret > 0
    
    def modify(self,username,data):
        ret = self.collection.update({"name":username},{"$set":data})
        return ret 
    
    def getInfo(self,username):
        ret = self.collection.find_one({"name":username})
        return ret
        
    
class Post:
    def __init__(self):
        self.collection = mongo.post
        pass
    
    def newPost(self,title,content,username,tags):
        self.collection.insert(
        {"title":title,"content":content,"username":username,"created":int(time.time()),"dateline":int(time.time())})
        
    def modify(self,pid,data):
        data['dateline'] = int(time.time())
        ret = self.collection.update({"_id":pid},{"$set":data})
        return ret
    
    def delete(self,pid):
        ret = self.collection.remove({"_id":pid})
        return ret
    
    def getOne(self,pid):
        ret = self.collection.find_one({"_id":pid})
        return ret
    
    def getList(self,pos,num):
        ret = self.collection.find().sort("dateline",pymongo.DESCENDING).limit(num).skip(pos)
        if(ret):
            data = []
            for i in ret:
                data.append(i)
            return data
        else:
            return None
    
    def getCount(self,username=None):
        if(username):
            ret = self.collection.find({"username":username}).count()
        else:
            ret = self.collection.find().count()
        return ret
    
class Catalog:
    def __init__(self):
        self.collection = mongo.catalog
        pass
    
class Comments:
    def __init__(self):
        self.collection = mongo.comment
        pass
    
class Tag:
    def __init__(self):
        self.collection = mongo.tag
        pass
    
    


###
class Count:
    
    @staticmethod
    def get_by_key(key):
        tb = mongo.site_count
        count = tb.find_one({"key":key})
        if(not count):
            return None
        return count["count"]
    
    @staticmethod
    def key_incr(key):
        tb = mongo.site_count
        if(Count.get_by_key(key)):
            tb.update({"key":key},{"$inc":{"count":1}})
        else:
            tb.insert({"key":key,"count":1})
            
    @staticmethod
    def key_decr(key):
        tb = mongo.site_count
        if(Count.get_by_key(key)):
            tb.update({"key":key},{"$inc":{"count":-1}})
        
            
    @staticmethod
    #@memcached('get_site_counts', 300)
    def get_site_counts():
        site_info = []
        
        member_num = Count.get_by_key('member_auto_increment')
        if member_num:
            if int(member_num)>1:
                site_info.append(('会员',int(member_num)-1))
        
        node_num = Count.get_by_key('node_auto_increment')
        if node_num:
            if int(node_num)>1:
                site_info.append(('主题',int(node_num)-1))
            
        topic_num = Count.get_by_key('all-topic-num')
        if topic_num:
            site_info.append(('帖子',topic_num))
        
        comment_num = Count.get_by_key('all-comment-num')
        if comment_num:
            site_info.append(('回复',comment_num))
        return site_info

class Member:
    @staticmethod
    def get_by_name(name):
        u = User()
        u_obj = u.getInfo(name)
        if u_obj:
            return u_obj
        else:
            return None
    
    @staticmethod
    #@memcached('cur_user', 600, lambda name, sr_code, flag=1: name)
    def check_loged_user(name, sr_code, flag=1):
        u_obj = Member.get_by_name(name)
        if u_obj:
            member_dict = u_obj
            if int(member_dict['flag']) >= flag:
                code_list = [member_dict['code']]
                #code_md5 = md5(''.join(code_list)).hexdigest()
                if md5(''.join(code_list)).hexdigest() == sr_code:
                    return member_dict
                else:
                    return None
            else:
                return None
        else:
            return None
    
    @staticmethod
    def check_user_name(name):
        return Member.get_by_name(name)
    
    @staticmethod
    def add_user(name, pwmd5):
        udict = MEMBER_DICT.copy()
        #get use id
        cur_num = Count.get_by_key("member_auto_increment")
        if cur_num:
            member_id = cur_num["value"]
            udict['flag'] = 1
        else:
            member_id = 1
            udict['flag'] = 99
        
        udict['id'] = member_id
        udict['name'] = name
        udict['code'] = pwmd5
        udict['topic_time'] = 0
        udict['comment_time'] = 0
        udict['notice'] = 0
        udict['add'] = int(time.time())
        u = User()
        if u.newUser(udict):
            if Count.key_incr("member_auto_increment"):
                return udict['flag']
        return None
    
    @staticmethod
    def get_by_name_for_edit(name):
        udict = MEMBER_DICT.copy()
        udict['id'] = ""
        udict['name'] = ''
        udict['code'] = ''
        udict['add'] = ''
        udict['topic_time'] = 0
        udict['comment_time'] = 0
        udict['notice'] = 0
        if name:
            m_obj = Member.get_by_name(name)
            return  m_obj
        else:
            return udict
    
    @staticmethod
    def set_flag(name, flag):
        u_obj = Member.get_by_name(name)
        if u_obj:
            if u_obj['flag'] != flag:
                u = User()
                return u.modify(name, {"flag":flag})
        return False
    
    @staticmethod
    def set_avatar(name, avatar):
        u_obj = Member.get_by_name(name)
        if u_obj:
            u = User()
            return u.modify(name, {"avatar":avatar})
        return False
    
    @staticmethod
    def add_key_rencent_topic(name, topickey):
        rt_obj = Commomkvdb.get_by_key('topic-'+name)
        if rt_obj:
            olist = rt_obj.split(',')
            if topickey not in olist:
                olist.insert(0, topickey)
                Commomkvdb.save('topic-'+name, ','.join(olist[:MEMBER_RECENT_TOPIC]))
        else:
            Commomkvdb.save('topic-'+name, topickey)
    
    @staticmethod
    def add_key_rencent_comment_topic(name, topickey):
        rt_obj = Commomkvdb.get_by_key('comment-topic-'+name)
        if rt_obj:
            olist = rt_obj.split(',')
            if topickey not in olist:
                olist.insert(0, topickey)
                Commomkvdb.save('comment-topic-'+name, ','.join(olist[:MEMBER_RECENT_TOPIC]))
        else:
            Commomkvdb.save('comment-topic-'+name, topickey)
    
class Node:
    @staticmethod
    def add_node_key(node_key):
        keys = Commomkvdb.get_by_key('recent_view_node')
        if keys:
            keys_list = keys.split(',')
            if node_key not in keys_list:
                keys_list.insert(0, node_key)
                Commomkvdb.save('recent_view_node', ','.join(keys_list[:10]))
                clear_cache_multi(['recent_view_node'])
        else:
            Commomkvdb.save('recent_view_node', node_key)
            clear_cache_multi(['recent_view_node'])
        
    
    @staticmethod
    #@memcached('recent_view_node', 300)
    def get_recent_node():
        keys = Commomkvdb.get_by_key('recent_view_node')
        if keys:
            objs = []
            for key in keys.split(','):
                value = Commomkvdb.get_by_key(key)
                if value:
                    n_obj = decode_dict(value)
                    objs.append((key, n_obj['name']))
            return objs
        else:
            return None
    
    @staticmethod
    def get_max_node_id():
        cur_num = Commomkvdb.get_by_key('node_auto_increment')
        if cur_num:
            id = str(cur_num)
        else:
            id = '1'
        return int(id)-1
    
    @staticmethod
    #@memcached('newest_add_node', 600)
    def get_newest():
        tb = mongo.node
        ret = tb.find().limit(10).sort("created",pymongo.DESCENDING)
        if(ret):
            data = {}
            for i in ret:
                data[str(i["_id"])] = i['name']
            return data.items()
        else:
            return None
    
    @staticmethod
    #@memcached('get_hot_node', 3600)
    def get_hot_node():
        tb = mongo.node
        ret = tb.find().limit(10).sort("created",pymongo.DESCENDING)
        if(ret):
            data = {}
            for i in ret:
                data[str(i["_id"])] = i['name']
            return data.items()
        else:
            return None
    
    @staticmethod
    def get_by_key(key):
        #n_obj_str = Commomkvdb.get_by_key(key)
        key = bson.ObjectId(key)
        tb = mongo.node
        n_obj = tb.find_one({"_id":key})
        if n_obj:
            return n_obj
        else:
            return None
    
    @staticmethod
    def get_by_name(name):
        #n_obj_str = Commomkvdb.get_by_key(key)
        tb = mongo.node
        n_obj = tb.find_one({"name":name})
        if n_obj:
            return n_obj
        else:
            return None
    
    @staticmethod
    def get_by_id_for_edit(id):
        if id:
            id = bson.ObjectId(id)
            tb = mongo.node
            n_obj = tb.find_one({"_id":id})
            return n_obj
        else:
            return NODE_DICT.copy()
        
    @staticmethod
    def incr_count(id,num):
        if id:
            id = bson.ObjectId(id)
            tb = mongo.node
            ret = tb.update({"_id":id},{"$inc":{"count":num}})
            return ret
        else:
            return None
    
    @staticmethod
    def decr_count(id,num):
        if id:
            id = bson.ObjectId(id)
            tb = mongo.node
            ret = tb.update({"_id":id},{"$inc":{"count":-num}})
            return ret
        else:
            return None
    
    @staticmethod
    def set_node(id, name, imgurl, about):
        tb = mongo.node
        if id:
            #n_obj_str = Commomkvdb.get_by_key('n-' + id)
            #ndict = decode_dict(n_obj_str)
            id = bson.ObjectId(id)
            ndict = {}
            ndict['name'] = name
            ndict['imgurl'] = imgurl
            ndict['about'] = about
            
            ret = tb.update({"_id":id},{"$set":ndict})
            if ret:
                clear_cache_multi(['newest_add_node'])
                return id #True
            else:
                return False
        else:
            ndict = NODE_DICT.copy()
            #get node id
            ndict['name'] = name
            ndict['imgurl'] = imgurl
            ndict['about'] = about
            ndict['created'] = int(time.time())
            
            ret = tb.insert(ndict)
            if ret:
                if Count.key_incr("node_auto_increment"):
                    clear_cache_multi(['newest_add_node'])
                    return str(ret) #True
            return False
    
    @staticmethod
    #@memcached('get_page_topic', 300, lambda node_id, from_id, to_id: "%s:%s"%(str(node_id), str(from_id)))
    def get_page_topic(node_id, pos, num):
        tb = mongo.topic
        ret = tb.find({"nodeid":node_id}).sort("add",pymongo.DESCENDING).skip(pos).limit(num)
        if(ret):
            data = {}
            for i in ret:
                u = Member.get_by_name(i['author'])
                i['avatar'] = u['avatar']
                data[str(i['_id'])] = i
            return data.items()
        else:
            return None

class Topic:
    @staticmethod
    def get_by_key(key):
        #t_obj_str = Commomkvdb.get_by_key(key)
        tb = mongo.topic
        key = bson.ObjectId(key)
        t_obj = tb.find_one({"_id":key})
        if t_obj:
            return t_obj
        else:
            return None    
    
    @staticmethod
    def get_by_title(title):
        #t_obj_str = Commomkvdb.get_by_key(key)
        tb = mongo.topic
        t_obj = tb.find_one({"title":title})
        if t_obj:
            return t_obj
        else:
            return None   
        
    @staticmethod
    def get_recent_topic(num = None):
        #t_obj_str = Commomkvdb.get_by_key(key)
        tb = mongo.topic
        if(num == None):
            num = RECENT_POST_NUM
        elif(num == 0):
            num = tb.find().count()
        t_obj = tb.find().sort("add",pymongo.DESCENDING).skip(0).limit(num)
        if t_obj:
            data = {}
            for i in t_obj:
                u = Member.get_by_name(i['author'])
                i['avatar'] = u['avatar']
                data[str(i['_id'])] = i
            return data.items()
        else:
            return None
    
    @staticmethod
    def add(topic_dict):
        #topic_key = 't-%s-%s' % (topic_dict['nodeid'], str(topic_id))
        tb = mongo.topic
        #ret = tb.find({"tid":topic_id}).count()
        #if(ret > 0):
        #    ret = tb.update({"tid":topic_id},{"$set":topic_dict})
        #else:
        topic_id = tb.insert(topic_dict)
        if topic_id:
            Count.key_incr("all-topic-num")
            return str(topic_id)
        else:
            return None
        
    @staticmethod
    def delete(topic_id):
        #topic_key = 't-%s-%s' % (topic_dict['nodeid'], str(topic_id))
        tb = mongo.topic
        #ret = tb.find({"tid":topic_id}).count()
        #if(ret > 0):
        #    ret = tb.update({"tid":topic_id},{"$set":topic_dict})
        #else:
        topic_id = bson.ObjectId(topic_id)
        ret = tb.remove({"_id":topic_id})
        if topic_id:
            Count.key_decr("all-topic-num")
            return topic_id
        else:
            return None
    
    @staticmethod
    def update(topic_id,topic_dict):
        #topic_key = 't-%s-%s' % (topic_dict['nodeid'], str(topic_id))
        tb = mongo.topic
        topic_id = bson.ObjectId(topic_id)
        ret = tb.find({"_id":topic_id}).count()
        if(ret > 0):
            ret = tb.update({"_id":topic_id},{"$set":topic_dict})
        else:
            ret = False
        return ret
    
    @staticmethod
    def incr_by_field(topic_id,field,num):
        tb = mongo.topic
        topic_id = bson.ObjectId(topic_id)
        ret = tb.find({"_id":topic_id}).count()
        if(ret > 0):
            ret = tb.update({"_id":topic_id},{"$inc":{field:num}})
        else:
            ret = False
        return ret
    
    
    
class Comment:
    
    @staticmethod
    def get_by_key(key):
        tb = mongo.comment
        key = bson.ObjectId(key)
        t_obj = tb.find_one({"_id":key})
        print(t_obj)
        if t_obj:
            return t_obj
        else:
            return None
    
    @staticmethod
    #@memcached('get_comments', 300, lambda t_key, from_id, to_id: "%s:%s"%(str(t_key), str(from_id)))
    def get_comments(t_key, pos, num):
        objs = []
        tb = mongo.comment
        objs = tb.find({"tid":t_key}).skip(pos).limit(num).sort("add",pymongo.DESCENDING)
        if(objs):
            data = []
            for i in objs:
                data.append(i)
            return data
        else:
            return None
    
    @staticmethod
    def new_comment(data):
        tb = mongo.comment
        ret = tb.insert(data)
        if(ret):
            Count.key_incr("all-comment-num")
            Topic.incr_by_field(data['tid'], "cnum", 1)
            return str(ret)
        return ret
        
class Commomkvdb:
    @staticmethod
    def get_by_key(key):
        tb = mongo.commonkv
        t_obj = tb.find_one({"key":key})
        if t_obj:
            return decode_dict(t_obj["value"])
        else:
            return None
    
    @staticmethod
    def save(key, my_dict):
        tb = mongo.commonkv
        my_dict = encode_dict(my_dict)
        if(Commomkvdb.get_by_key(key)):
            return tb.update({"key":key}, {"$set":{"value":my_dict}})
        else:
            return tb.insert({"key":key,"value":my_dict})
    
    @staticmethod
    def incr(key, num):
        tb = mongo.commonkv
        if(Commomkvdb.get_by_key(key)):
            return tb.update({"key":key}, {"$inc":{"value":num}})
        else:
            return tb.insert({"key":key,"value":1})
        
    
    @staticmethod
    def add_key_rencent_topic(key, topickey):
        rt_obj = Commomkvdb.get_by_key(key)
        if rt_obj:
            olist = rt_obj.split(',')
            if topickey in olist:
                olist.remove(topickey)
            olist.insert(0, topickey)
            Commomkvdb.save(key, ','.join(olist[:RECENT_POST_NUM]))
        else:
            Commomkvdb.save(key, topickey)
    
    @staticmethod
    #@memcached('get_topic_by_keys', 300, lambda keys_list_key: keys_list_key)
    def get_topic_by_keys(keys_list_key):
        obj = Commomkvdb.get_by_key(keys_list_key)
        if obj:
            objs = []
            for key in obj.split(','):
                value = Commomkvdb.get_by_key(key)
                if value:
                    objs.append((key, decode_dict(value)))
            return objs
        else:
            return []
    
    @staticmethod
    def get_notifications(username, keys_list_str):
        if keys_list_str:
            objs = []
            for key in keys_list_str.split(','):
                value = Commomkvdb.get_by_key(key)
                if value:
                    objs.append((key, decode_dict(value)))
            return objs
        else:
            return []
    
    @staticmethod
    #@memcached('get_comment_topic_by_keys', 300, lambda keys_list_key: keys_list_key)
    def get_comment_topic_by_keys(keys_list_key):
        obj = Commomkvdb.get_by_key(keys_list_key)
        if obj:
            objs = []
            for key in obj.split(',')[:10]:
                value = Commomkvdb.get_by_key(key)
                if value:
                    objs.append((key, decode_dict(value)['title']))
            return objs
        else:
            return []
    
